package com.ylp.sys.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylp.common.exception.ServiceException;
import com.ylp.common.response.PageResult;
import com.ylp.common.utils.StringUtils;
import com.ylp.sys.auth.entity.UserInfo;
import com.ylp.sys.domain.dto.RoleDto;
import com.ylp.sys.domain.dto.RolePageDto;
import com.ylp.sys.domain.entity.SysMenu;
import com.ylp.sys.domain.entity.SysRole;
import com.ylp.sys.domain.entity.SysRoleMenu;
import com.ylp.sys.domain.vo.MenuVo;
import com.ylp.sys.mapper.SysRoleMapper;
import com.ylp.sys.mapper.SysRoleMenuMapper;
import com.ylp.sys.service.SysMenuService;
import com.ylp.sys.service.SysRoleService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统角色表 服务实现类
 * </p>
 *
 * @author cc
 * @since 2024-07-24
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    private final SysRoleMapper roleMapper;
    private final SysRoleMenuMapper roleMenuMapper;
    private final SysMenuService menuService;

    public SysRoleServiceImpl(SysRoleMapper roleMapper, SysRoleMenuMapper roleMenuMapper, SysMenuService menuService) {
        this.roleMapper = roleMapper;
        this.roleMenuMapper = roleMenuMapper;
        this.menuService = menuService;
    }

    /**
     * 获取角色选择列表
     * @return
     */
    @Override
    public List<Map<String, Object>> getSelectList() {
        List<Map<String, Object>> list = null;
        try {
            List<SysRole> roles = roleMapper.selectList(null);
            if (ObjectUtil.isNotNull(roles)) {
                list = new ArrayList<>();
                for (SysRole role: roles) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("roleId", role.getId());
                    map.put("roleName", role.getRoleName());
                    list.add(map);
                }
            }
        } catch (Exception e) {
            throw new ServiceException("查询失败");
        }
        return list;
    }

    /**
     * 分页查询
     * @param rolePageDto
     * @return
     */
    @Override
    public PageResult<SysRole> pageList(RolePageDto rolePageDto) {
        //int statue = rolePageDto.getStatus();
        IPage<SysRole> page = null;
        // like 条件构造
        try {
            LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.like(StringUtils.isNotEmpty(rolePageDto.getRoleName()), SysRole::getRoleName, rolePageDto.getRoleName())
                    .like(StringUtils.isNotEmpty(rolePageDto.getRoleLable()), SysRole::getRoleLabel, rolePageDto.getRoleLable());
            //.like(SysRole::getStatus, rolePageDto.getStatus());
            if (rolePageDto.getStatus() != -1) {
                wrapper.eq(SysRole::getStatus, rolePageDto.getStatus());
            }
            // 分页构造
            page = new Page<>(rolePageDto.getCurrentPage(), rolePageDto.getPageSize());
            roleMapper.selectPage(page, wrapper);
        } catch (Exception e) {
            throw new ServiceException("查询失败");
        }
        return new PageResult<SysRole>(page.getRecords(), page.getTotal());
    }

    /**
     * 添加角色
     * @param roleDto
     * @return
     */
    @Transactional
    @Override
    public void addRole(RoleDto roleDto) {
        // 添加角色
        UserInfo userLoginInfo = (UserInfo) StpUtil.getSession().get("userInfo");
        String userName = userLoginInfo.getUsername();
        SysRole role = new SysRole();
        BeanUtil.copyProperties(roleDto, role);
        role.setCreator(userName);
        role.setUpdater(userName);
        role.setDeleted(0);
        roleMapper.insert(role);
        Long roleId = role.getId();
        for (Long menuId: roleDto.getMenuIds()) {
            SysRoleMenu roleMenu = new SysRoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menuId);
            roleMenuMapper.insert(roleMenu);
        }
    }

    /**
     * 获取角色和菜单ids
     * @param id
     * @return
     */
    @Override
    public RoleDto getRoleAndMenuIdsById(Long id) {
        RoleDto roleDto = new RoleDto();
        try {
            SysRole role = roleMapper.selectById(id);
            BeanUtil.copyProperties(role, roleDto);
            LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysRoleMenu::getRoleId, role.getId());
            List<SysRoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
            List<Long> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
            List<Long> selectMenuIds = menuIds.stream().distinct().collect(Collectors.toList());
            roleDto.setMenuIds(selectMenuIds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException();
        }
        return roleDto;
    }




    /**
     * 修改角色信息和菜单
     * @param roleDto
     */
    @Transactional
    @Override
    public void updateAndMenus(RoleDto roleDto) {
        UserInfo userLoginInfo = (UserInfo) StpUtil.getSession().get("userInfo");
        String userName = userLoginInfo.getUsername();
        // 更新角色信息
        SysRole role = new SysRole();
        BeanUtil.copyProperties(roleDto, role);
        role.setUpdater(userName);
        roleMapper.updateById(role);
        // 删除角色菜单并重新关联
        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRoleMenu::getRoleId, role.getId());
        roleMenuMapper.delete(wrapper);
        Long roleId = role.getId();
        for (Long menuId: roleDto.getMenuIds()) {
            SysRoleMenu roleMenu = new SysRoleMenu();
            roleMenu.setMenuId(menuId);
            roleMenu.setRoleId(roleId);
            roleMenuMapper.insert(roleMenu);
        }
    }

    /**
     * 删除角色
     * @param ids
     */
    @Transactional
    @Override
    public void deleteByIds(List<Long> ids) {
        roleMapper.deleteBatchIds(ids);
        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysRoleMenu::getRoleId, ids);
        roleMenuMapper.delete(wrapper);
    }

    @Override
    public void updateStatus(SysRole role) {
        try {
            LambdaUpdateWrapper<SysRole> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(SysRole::getStatus, role.getStatus());
            wrapper.eq(SysRole::getId, role.getId());
            roleMapper.update(wrapper);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("修改失败");
        }
    }

    /**
     * 获取授权和未授权数据
     * @param roleId
     * @return
     */
    @Override
    public Map<String, Object> searchAuthAndNot(Long roleId) {
        Map<String, Object> resMap = new HashMap<>();
        try {
            // 查询所有菜单
            List<SysMenu> menus = menuService.list();
            // 查询已授权菜单
            LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysRoleMenu::getRoleId, roleId);
            List<SysRoleMenu> roleMenus = roleMenuMapper.selectList(wrapper);
            List<Long> menuids = roleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
            List<SysMenu> authList = menuService.getListByIds(menuids);
            if (!authList.isEmpty()) {
                List<SysMenu> authAllList = searchMenuAndParentMenu(menus, authList.stream().map(SysMenu::getId).collect(Collectors.toList()));
                List<MenuVo> menuVos = menuService.buileMenuTree(authAllList);
                //List<MenuVo> menuVosFilter = filterDirCheckIsChild(menuVos);
                // 封装map
                resMap.put("auth", menuVos);
            }

            // 查询未授权菜单
            List<SysMenu> NoAuthList = null;
            if (menuids.isEmpty()) {
                NoAuthList = menuService.list();
            } else {
                NoAuthList = menuService.getListNotIds(menuids);
            }
            if (!NoAuthList.isEmpty()) {
                List<SysMenu> NoAuthAllList = searchMenuAndParentMenu(menus, NoAuthList.stream().map(SysMenu::getId).collect(Collectors.toList()));
                List<MenuVo> menuVos1 = menuService.buileMenuTree(NoAuthAllList);
                //List<MenuVo> menuVosFilter1 = filterDirCheckIsChild(menuVos1);
                resMap.put("notAuth", menuVos1);
            }
        } catch (Exception e) {
            throw new ServiceException("查询失败");
        }
        return resMap;
    }

    // 过滤，没有子菜单的目录
    private List<MenuVo> filterDirCheckIsChild(List<MenuVo> menuVos) {
        List<MenuVo> menuVos1 = menuVos.stream().filter(item -> !item.getChildren().isEmpty()).collect(Collectors.toList());
        return menuVos1;
    }

    private List<SysMenu> searchMenuAndParentMenu(List<SysMenu> menus, List<Long> ids) {
        List<SysMenu> lis = new ArrayList<>();
        for(Long id: ids) {
            lis.addAll(findAllParents(menus, id));
        }
        return selectOnes(lis);
    }

    // 过滤重复菜单及其没有子菜单的目录
    private List<SysMenu> selectOnes(List<SysMenu> menus) {
        List<SysMenu> menuList = new ArrayList<>();
        for (SysMenu menu: menus) {
            SysMenu sysMenu = findMenuItemById(menuList, menu.getId());
            if (sysMenu == null) {
                menuList.add(menu);
            }
        }
        return menuList;
    }

    // 递归查询所有父菜单
    public List<SysMenu> findAllParents(List<SysMenu> menus, Long id) {
        List<SysMenu> parents = new ArrayList<>();
        SysMenu current = findMenuItemById(menus, id);
        while (current != null && current.getParentId() != 0) {
            current = findMenuItemById(menus, current.getParentId());
            if (current != null) {
                parents.add(0, current); // 在列表开头插入，以保持顺序
            }
        }
        // 如果需要包括当前菜单项本身，可以在这里添加
        parents.add(0, findMenuItemById(menus, id));
        return parents;
    }

    // 根据ID查找菜单项
    private SysMenu findMenuItemById(List<SysMenu> menus, long id) {
        for (SysMenu item : menus) {
            if (item.getId() == id) {
                return item;
            }
        }
        return null;
    }

}
